use super::{options::Options, BaseFitneser, Fitneser};
use crate::window::{UIState, Window};
use log::debug;
use std::{
  error::Error,
  sync::{mpsc::Sender, Arc, Mutex},
};

pub struct Destroyer {
  _super: BaseFitneser,
}

impl Destroyer {
  pub fn new(mutex: Arc<Mutex<bool>>) -> Self {
    Destroyer {
      _super: BaseFitneser::new(mutex),
    }
  }
}

impl Fitneser for Destroyer {
  fn init(&mut self, opts: &Options, asset_path: String) -> Result<bool, Box<dyn Error>> {
    self._super.setup(opts, asset_path);
    Ok(true)
  }

  /// 运行练体
  /// ### 返回值
  /// * `true` 外部正常结束
  /// * `false` 异常结束
  fn run(&mut self, win: &Window, msg_tx: &Sender<String>) -> Result<bool, Box<dyn Error>> {
    debug!("destroyer is running");
    let mut _state = 0;
    loop {
      if !self._super.is_running() {
        return Ok(true);
      }
      self._super.try_repair(win)?;
      debug!("try_repair td");
      // if self._super.exit_no_die(win)? {
      //   let _ = msg_tx.send(format!("生命中低 退出游戏"));
      //   return Ok(false);
      // }
      if _state == 0 {
        _state = self._super.fetch_state(win)?;
      }
      // 吃东西
      if _state != 0 {
        let _ = msg_tx.send(format!("当前状态: {}", _state));
        // 如果需要退出 先捡起锤子 免得丢失
        if _state & (1 << 8) == 256 {
          self.pickup(win)?;
          self._super.exit_to_lobby(win)?;
          return Ok(false);
        }
        self._super.ensure_base(win, _state)?;
        // 温度过高
        if _state & 16 == 16 {
          let _ = msg_tx.send(format!("温度过高 冷静 1 分钟"));
          for _ in 0..60 {
            win.sleep(1000);
            if !self._super.is_running() {
              break;
            }
          }
        }
      }
      _state = 0;
      debug!("准备砸箱子");
      let mut _ticks = 0;
      loop {
        if !self._super.is_running() {
          return Ok(true);
        }
        // 检查掉线
        if self._super.check_lost(win)? {
          if !self._super.handle_lost(win)? {
            self._super.stop_running();
            let _ = msg_tx.send(format!("掉线无法重连"));
            return Ok(false);
          }
          break;
        }
        // 如果失败
        if !self.destroy(win)? {
          win.sleep(1000 * 3);
          break;
        }
        _ticks += 1;
        if _ticks % 10 == 0 {
          self._super.try_repair(win)?;
          _state = self._super.fetch_state(win)?;
          if _state == 0 {
            continue;
          }
          break;
        }
      }
      self.drop(win)?;
    }
  }
}

impl Destroyer {
  /// 摧毁
  fn destroy(&self, win: &Window) -> Result<bool, Box<dyn Error>> {
    self.pickup(win)?;
    win.ensure_ui(UIState::Tab, 1)?;
    // 摧毁
    win.mouse_move_to(360, 190)?;
    win.mouse_click_r()?;
    win.sleep(350);
    win.mouse_move_to(360, 190 + 93)?;
    win.sleep(50);
    if win.is_active(360, 190 + 85) {
      win.mouse_click_l()?;
      win.sleep(500);
      self._super.look_status(win)?;
      // 等待并取消
      for _ in 0..8 {
        win.sleep(1000 * [1, 2, 3][self._super.opts.sub_type as usize]);
        if !self._super.is_running() {
          break;
        }
      }
      win.release_key("ctrl")?;
      win.sleep(50);
      win.tap_key("esc")?;
      win.sleep(50);
      win.tap_key("esc")?;
      win.sleep(50);
      win.tap_key("esc")?;
      win.sleep(50);
      return Ok(true);
    }
    Ok(false)
  }

  fn pickup(&self, win: &Window) -> Result<(), Box<dyn Error>> {
    win.ensure_ui(UIState::Tab, 1)?;
    // 拿起锤子
    win.mouse_move_to(390, 90)?;
    win.mouse_click_r()?;
    win.sleep(350);
    win.mouse_move_to(390, 90 + 18)?;
    win.sleep(50);
    if win.is_active(390, 90 + 18) {
      win.mouse_click_l()?;
      win.sleep(2000);
    }
    Ok(())
  }

  fn drop(&self, win: &Window) -> Result<bool, Box<dyn Error>> {
    win.ensure_ui(UIState::Tab, 1)?;
    win.mouse_move_to(975, 605)?;
    win.sleep(50);
    win.mouse_click_r()?;
    win.sleep(250);
    win.mouse_move_to(975, 605 + 18)?;
    win.mouse_click_l()?;
    win.sleep(500);
    Ok(true)
  }
}
